
#include <ctime>
#include <iomanip>
using namespace std;

#include "stdlib.h"

#include "SimModels.h"
using namespace SimModels;

namespace SimModels {

 
/////////////////////////////////////////////////////////////////// putHeader()

void putHeader()
{
	// Run header
	ostream& simlog = simOutMgr.getStream();
	time_t curr = time(0);

	simOutMgr.pushMargin();
	simlog << "Date and time of run : " << ctime(&curr) << "Project : Lab #3";
    simOutMgr.advToMargin();
	simOutMgr.popMargin();

}//putHeader


 /////////////////////////////////////////////////////////////////////SpeakMsg
/*
	SpeakMsg::SpeakMsg(int Handler, string Description, string Speak)
		     :Message(Handler,Description)
	{
		content = Speak;
	}

   	void SpeakMsg::Insert()
	{
		int delta = 10;
		ostream& simlog = simOutMgr.getStream();


        simOutMgr.pushMargin();
		simlog << "SpeakMsg{ ";

		Put();

		simOutMgr.advToMargin();
		simlog << "}SpeakMsg ";
		simOutMgr.popMargin();

	}
    
    void SpeakMsg::Put()
	{
		ostream& simlog = simOutMgr.getStream();

		simOutMgr.pushMargin();
		Message::Put();
		simOutMgr.advToMargin();
		simlog << " content: " << content;
		simOutMgr.popMargin();
	}

*/
///////////////////////////////Card Message
	CardMsg::CardMsg(int Handler, std::string Description, Card::Suit cardsuit, int cardvalue)
		:Message(Handler, Description)
	{
		cardsuitmsg=cardsuit;
		cardvaluemsg=cardvalue;
	}

   	void CardMsg::Insert()
	{
		int delta = 10;
		ostream& simlog = simOutMgr.getStream();
        simOutMgr.pushMargin();
		simlog << "CardMsg{ ";
		Put();
		simOutMgr.advToMargin();
		simlog << "}CardMsg ";
		simOutMgr.popMargin();
	}
    
    void CardMsg::Put()
	{
		ostream& simlog = simOutMgr.getStream();
		simOutMgr.pushMargin();
		Message::Put();
		simOutMgr.advToMargin();
		simlog << " Card Suit: " << cardsuitmsg;
		simlog << " Card Value: " << cardvaluemsg;
		simOutMgr.popMargin();
	}


///////////////////////////////Action Message

	ActionMsg::ActionMsg(int Handler, std::string Description, Action::Choice typeofaction)
		:Message(Handler, Description)
	{
		content = typeofaction;
	}

   	void ActionMsg::Insert()
	{
		int delta = 10;
		ostream& simlog = simOutMgr.getStream();
        simOutMgr.pushMargin();
		simlog << "ActionMsg{ ";
		Put();
		simOutMgr.advToMargin();
		simlog << "}ActionMsg ";
		simOutMgr.popMargin();
	}
    
    void ActionMsg::Put()
	{
		ostream& simlog = simOutMgr.getStream();
		simOutMgr.pushMargin();
		Message::Put();
		simOutMgr.advToMargin();
		simlog << " Action: " << content;
		simOutMgr.popMargin();
	}

/////////////////////////////////////////////////////////////////////// Players

	Players::Players(int MaxAgents) throw(AppError):Message(0,"Players") 
	{   
		if( MaxAgents < 1 )throw AppError("MaxAgents must be >= 1! ","Players::Players()");
		agents     = new AGENTPTR[MaxAgents];
	    agentNames = new string[MaxAgents];
		numAgents  = MaxAgents;
		lastAgent  = -1;
	}

	Players::~Players()
	{
		delete[] agents; 
		delete[] agentNames;
	}

	int Players::getNumAgents()
	{
		return numAgents;
	}

    AGENTPTR Players::getAgent(string playerid) throw(AppError)
	{
		if( lastAgent != numAgents-1 ) 
			throw AppError("Protocol violation!  Agents have not been defined!",
			               "Players::getAgent(@1)");
		int i = 0;
        for(; i <= numAgents ; i++){
			if( agentNames[i] == playerid ) break;
		}

		if ( i > numAgents ) 
			throw AppError("Cannot identify Agent !",
                           "Players::getAgent(" + playerid + ")");
		else return agents[i];
	}

	AGENTPTR Players::getDealer()throw(AppError)
	{
		// This function should return a pointer to the dealer. It will be called by the initialization function
		// of both Gambler and Dealer
		// It only returns this so the program will compile. (This isn't the right/correct dealer)
		return (AGENTPTR)dealerptr;
		
	}

	AGENTPTR *Players::getGamblers()throw(AppError)
	{
		// This function should return a pointer to all of the Gamblers.
		// It will be called by the initialization function of Dealer
		// It only returns this so the program will compile. (This isn't the right/correct gambler array)
		//return new AGENTPTR; 
		return (AGENTPTR*)agents;
	}
/*
	AGENTPTR *Players::getOthers(int Num) throw(AppError)
	{
		if( lastAgent != numAgents-1 ) 
			throw AppError("Protocol violation!  Agents have not been defined!",
			               "Players::getOthers(@1)");

		// Selects a random subset of distinct Agents of size (Num).
		if( Num > numAgents ) 
			throw AppError("Number of random Agents requested exceeds number defined!",
			               "Players::getOthers(@2)");

		AGENTPTR *randomAgents = new AGENTPTR[Num];
		int n, j, k = 0;

		n = rand() % numAgents;
		randomAgents[k] = agents[n];
		while( k < Num-1 )
		{  n = rand() % numAgents;
		   for(j = 0; j <= k; j++)
		   {
			   if( agents[n] == randomAgents[j] ) break;
		   }//for
		   if( j > k )
		   {
			   randomAgents[++k] = agents[n];
		   }//if
		}//while
		return randomAgents;
	}
*/
    void Players::setAgent(string playerid, AGENTPTR agent) throw(AppError)
	{   
		lastAgent++;
		if( lastAgent >= numAgents )
			throw AppError("Agent overflow attempted!", 
			               "Players::setAgent(@1)");
		for(int i=0; i < lastAgent; i++)
		{
			if( playerid == agentNames[i] || agent == agents[i] )
				throw AppError("Duplicate definition of Agent attempted!",
				               "Players::setAgent(@2)");
		}//for
		agentNames[lastAgent] = playerid;
		agents[lastAgent]     = agent; 
	}
	void Players::setDealer(AGENTPTR dealer) throw(AppError)
	{
		//dealer->numGamblers = numAgents;
		dealerptr=dealer;
	}

    void Players::Insert()
	{    		
		ostream& simlog = simOutMgr.getStream();

		 simOutMgr.pushMargin();
		 simlog << "Players{ ";
		 Put();
		 simOutMgr.advToMargin();
		 simlog << "}Players ";
		 simOutMgr.popMargin();
	}//Insert

    void Players::Put()
	{
		ostream& simlog = simOutMgr.getStream();

		simOutMgr.pushMargin();
		for(int i = 0; i < numAgents; i++ )
		{   
			simlog << " agent[ " << i << " ] = " << agentNames[i];
			simOutMgr.advToMargin();
		}//for
        simOutMgr.popMargin();
	}//Put


	/*
////////////////////////////////////////////////////////////////////// Student

	Student::Student():Agent()
	{
	}


	Student::~Student()
	{
	}


	void Student::Extract() throw(TokenError)
	{
			string token;
			ifstream& fin = simInMgr.getStream();


			// Parse opening token
			fin >> token;
			if ( token != "Student{" ) 
			    throw TokenError(string("Incorrect Token, '" + token + "', expected 'Student{' !"),
                                 string("Student::Extract()"));
			
			// Parse data members
			Get();

			// Parse closing token
			fin >> token; 
			if ( token != "}Student" ) 
				throw TokenError(string("Incorrect Token '" + token + "', expected token '}Student' !"),
                                 string("Student::Get()"));
	}

	void Student::Get() throw(TokenError)
	{
		string token;
		ifstream& fin = simInMgr.getStream();

		// parse inherited members 
		Agent::Get(); 
		
		// parse token "QuestDelay"
		fin >> token;
		if ( token != "questdelay:" ) 
		   throw TokenError(string("Incorrect Token '" + token + "', expected 'questdelay:' !"),
                            string("Student::Get(@1)"));

		// Parse question delay
		fin >> token;
		questDelay = atoi(token.c_str());  
		
		// parse token "AnsrDelay"
		fin >> token; 
		if ( token != "ansrdelay:" ) 
		throw TokenError(string("Incorrect Token '" + token + "', expected 'ansrdelay:' !"),
                         string("Student::Get(@2)"));

		// Parse answer delay
		fin >> token;
		ansrDelay = atoi(token.c_str());

		// parse token "scandelay"
		fin >> token; 
		if ( token != "scandelay:" ) 
		throw TokenError(string("Incorrect Token '" + token + "', expected 'scandelay:' !"),
                         string("Student::Get(@3)"));

		// Parse scandelay
		fin >> token;
		scanDelay = atoi(token.c_str());

		// parse token "interest"
		fin >> token; 
		if ( token != "interest:" ) 
		throw TokenError(string("Incorrect Token '" + token + "', expected 'interest:' !"),
                         string("Student::Get(@4)"));

		// Parse interest
		fin >> token;
		interest = atoi(token.c_str());
	}

	void Student::Insert()
	{
		ostream& simlog = simOutMgr.getStream();

		simOutMgr.pushMargin();
		simlog << "Student{ ";
		Put();
		simOutMgr.advToMargin();
		simlog << "}Student ";
		simOutMgr.popMargin();
	}

	void Student::Put()
	{
		ostream& simlog = simOutMgr.getStream();
	
		simOutMgr.pushMargin();
		Agent::Put();
		simOutMgr.advToMargin();
		simlog << " questdelay: " << questDelay;
		simOutMgr.advToMargin();
		simlog << " ansrdelay: "  << ansrDelay;
		simOutMgr.advToMargin();
		simlog << " scandelay: "  << scanDelay;
		simOutMgr.advToMargin();
		simlog << " interest: "   << interest;
		simOutMgr.popMargin();
	}


	void Student::Initialize(MSGPTR players)
	{
		// Obtaining player's handle
		me  = (Student *)((Players *)players)->getAgent(NameOf());
		// Pick and Agent at random to send a question to.
		you = ((Players *)players)->getOthers(interest);
        
		// Construct new message
		Message *scanMsg = ((Student *)me)->AcceptScanComplete();
 
		// Construct new Event
		Event e( scanDelay , me , me, scanMsg );

		// Post Event
		theEventMgr.postEvent(e);

	}

	 void Student::Dispatch  (MSGPTR msg)
	{
		int h          = msg->getHandler();
		switch( h )
		{
		case 1: { 
					string content = ((SpeakMsg *)msg)->getContent();
					doQuestions(content);
					break;
				}
		case 2: {
					string content = ((SpeakMsg *)msg)->getContent();
					doAnswers(content);
					break;
				}
		case 3: doScanComplete(); break;
		case 4: doTerminate(); break;
		default: throw AppError("Undefined handler ID!", "Student::Dispatch()");
		}
        
	}//Dispatch

	SpeakMsg *Student::AcceptQuestion(string aquestion)
	{
		return new SpeakMsg(1,"question",aquestion);
	}

	SpeakMsg *Student::AcceptAnswer(string response)
	{
		return new SpeakMsg(2,"answer",response);
	}

	
	Message  *Student::AcceptScanComplete()
	{
		return new Message(3,"Scan is complete for " + NameOf());
	}

	Message  *Student::AcceptTerminate()
	{   
		return new Message(4,"Terminate: " + NameOf());
	}


	void Student::doScanComplete()
	{
		int time = theEventMgr.clock() + questDelay;
		lastyou = 0;
		// Construct new message
		SpeakMsg *strMsg = ((Student *)you[lastyou])->AcceptQuestion("What is your name?");
 
		// Construct new Event
		Event e( time , me , you[lastyou] , strMsg );

		// Post Event
		theEventMgr.postEvent(e);
	}

	void Student::doQuestions(string question)
	{
		int time = theEventMgr.clock() + ansrDelay ;
		SpeakMsg *strMsg = AcceptAnswer("My name is:" + NameOf() + "!" );

		Event e( time , me , theEventMgr.getSendr() , strMsg );
		
		theEventMgr.postEvent(e);
	}

	void Student::doAnswers(string response)
	{
		ostream& simlog = simOutMgr.getStream();

		simOutMgr.newLine();
		simOutMgr.pushMargin();
		simlog << "At time: " << theEventMgr.clock();
		simlog << ", Student: " + NameOf() + " received the following response from: " + theEventMgr.getSendr()->NameOf();
		simOutMgr.advToMargin();
		simlog << response;
		simOutMgr.popMargin();
		simOutMgr.advToMargin();

		if( lastyou < interest-1 )
		{
			int time = theEventMgr.clock() + questDelay;
			SpeakMsg *strMsg = ((Student *)you[++lastyou])->AcceptQuestion("What is your name?");
			
			// Construct new Event
			Event e( time , me , you[lastyou] , strMsg );

		    // Post Event
		    theEventMgr.postEvent(e);
		}//if

	}


	void Student::doTerminate()
	{
		ostream& simlog = simOutMgr.getStream();

		simOutMgr.newLine();
		simOutMgr.pushMargin();
		simlog << "At time: " << theEventMgr.clock();
		simlog << ", Student: " + NameOf() + " is terminating!";
		simOutMgr.advToMargin();
		simlog << *me;
		simOutMgr.popMargin();
		simOutMgr.advToMargin();
	}

*/

////////////////////////////////////////////////////////////////////// Dealer

	Dealer::Dealer():Agent()
	{
	}


	Dealer::~Dealer()
	{
	}


	void Dealer::Extract() throw(TokenError)
	{
			string token;
			ifstream& fin = simInMgr.getStream();


			// Parse opening token
			fin >> token;
			if ( token != "Dealer{" ) 
			    throw TokenError(string("Incorrect Token, '" + token + "', expected 'Dealer{' !"),
                                 string("Dealer::Extract()"));
			
			// Parse data members
			Get();

			// Parse closing token
			fin >> token; 
			if ( token != "}Dealer" ) 
				throw TokenError(string("Incorrect Token '" + token + "', expected token '}Dealer' !"),
                                 string("Dealer::Get()"));
	}

	void Dealer::Get() throw(TokenError)
	{
		string token;
		ifstream& fin = simInMgr.getStream();

		// parse inherited members 
		Agent::Get(); 
//NEW		
		// parse token "DealerStrategy"
		fin >> token;
		if ( token != "dealerstrategy:" ) 
		   throw TokenError(string("Incorrect Token '" + token + "', expected 'dealerstrategy:' !"),
                            string("Dealer::Get(@1)"));

		// Parse dealer strategy
		fin >> token;
		dealerStrategy = atoi(token.c_str());  
		startDelay = 1;//NEW - arbitrarily set startdelay instead of scanning it in
//END NEW	

		//parse simulations
		fin >> token;
		if ( token != "simulations:" ) 
		   throw TokenError(string("Incorrect Token '" + token + "', expected 'simulations:' !"),
                            string("Dealer::Get(@2)"));
		// Parse numsim
		fin >> token;
		numSims = atoi(token.c_str());  

		
		//parse simulations
		fin >> token;
		if ( token != "#gamblers:" ) 
			throw TokenError(string("Incorrect Token '" + token + "', expected '#gamblers:' !"),
                            string("Dealer::Get(@2)"));
		// Parse numsim
		fin >> token;
		numGamblers = atoi(token.c_str()); 

/*	No need to parse any of these
		// parse token "AnsrDelay"
		fin >> token; 
		if ( token != "ansrdelay:" ) 
		throw TokenError(string("Incorrect Token '" + token + "', expected 'ansrdelay:' !"),
                         string("Dealer::Get(@2)"));

		// Parse answer delay
		fin >> token;
		ansrDelay = atoi(token.c_str());

		// parse token "scandelay"
		fin >> token; 
		if ( token != "scandelay:" ) 
		throw TokenError(string("Incorrect Token '" + token + "', expected 'scandelay:' !"),
                         string("Dealer::Get(@3)"));

		// Parse scandelay
		fin >> token;
		scanDelay = atoi(token.c_str());

		// parse token "interest"
		fin >> token; 
		if ( token != "interest:" ) 
		throw TokenError(string("Incorrect Token '" + token + "', expected 'interest:' !"),
                         string("Dealer::Get(@4)"));

		// Parse interest
		fin >> token;
		interest = atoi(token.c_str());
*/
	}

	void Dealer::Insert()
	{
		ostream& simlog = simOutMgr.getStream();

		simOutMgr.pushMargin();
		simlog << "Dealer{ ";
		Put();
		simOutMgr.advToMargin();
		simlog << "}Dealer ";
		simOutMgr.popMargin();
	}

	void Dealer::Put()
	{
		ostream& simlog = simOutMgr.getStream();
	
		simOutMgr.pushMargin();
		Agent::Put();
		simOutMgr.advToMargin();
		simlog << " dealerstrategy: " << dealerStrategy;//NEW
/*	No need to log any of these
		simOutMgr.advToMargin();
		simlog << " ansrdelay: "  << ansrDelay;
		simOutMgr.advToMargin();
		simlog << " scandelay: "  << scanDelay;
		simOutMgr.advToMargin();
		simlog << " interest: "   << interest;
*/
		simOutMgr.popMargin();
	}


	void Dealer::Initialize(MSGPTR players)
	{
		int time = startDelay + theEventMgr.clock();
		// This needs to be the function that gives the dealer a pointer to itself
		me  = (Dealer *)((Players *)players)->getDealer();
		// This needs to be the function that gives the dealer an array of pointers to all of the gamblers
		gamblers2 = ((Players *)players)->getGamblers();
		
        numCards = 0;
		currentGambler = 0;
		currentCard = 0;
		for(int i=0; i<11; i++)
			hand[i] = Card();

		// Construct new message
		Message *startMsg = ((Dealer *)me)->AcceptStartComplete();
		
 
		// Construct new Event
		Event e( time , me , me, startMsg );
		

		// Post Event
		theEventMgr.postEvent(e);

	}

	 void Dealer::Dispatch  (MSGPTR msg)
	{
		int h          = msg->getHandler();
		switch( h )
		{
					case 1: { 
				//	string content = ((SpeakMsg *)msg)->getContent(); Not being used. Kept for posterity
					int value = ((CardMsg *)msg)->getValue();
					Card::Suit mysuit = ((CardMsg *)msg)->getSuit();
					doAcceptCard(value, mysuit);
					break;
				}
		case 2: {
					//string content = ((SpeakMsg *)msg)->getContent();
					doAcceptTurn();
					break;
				}/*
		case 1: { 
					string content = ((SpeakMsg *)msg)->getContent();
					doQuestions(content);
					break;
				}
		case 2: {
					string content = ((SpeakMsg *)msg)->getContent();
					doAnswers(content);
					break;
				}*/
		case 3: doStartComplete(); break;
		
		
		case 4: doEndGame(); break;
		case 5: doTerminate(); break;
		case 6: {
				Action::Choice mychoice = ((ActionMsg*)msg)->getChoice();	
				doDealerAction(mychoice); 
				break;
				}
		case 7: doCardReceived(); break;
		case 8: {
				Action::Choice theirchoice = ((ActionMsg*)msg)->getChoice();
				doPlayerAction(theirchoice); 
				break;
				}
		default: throw AppError("Undefined handler ID!", "Dealer::Dispatch()");
		}
        
	}//Dispatch
/*
	SpeakMsg *Dealer::AcceptQuestion(string card1)
	{
		return new SpeakMsg(1,"question",card1);
	}

	SpeakMsg *Dealer::AcceptAnswer(string gAct)
	{
		return new SpeakMsg(6,"answer",gAct);
	}
*/	
	 CardMsg *Dealer::AcceptCard(Card::Suit mysuit, int value)
	{
		return new CardMsg(1, "Card Message", mysuit, value);
	}

	Message *Dealer::AcceptTurn()
	{
		return new Message(2,"It is" + NameOf() + "'s turn.");
	}
	ActionMsg *Dealer::AcceptDealerAction(Action::Choice dAct)
	{
		return new ActionMsg(6,"answer",dAct);
	}

	ActionMsg *Dealer::AcceptGamblerAction(Action::Choice gAct)
	{
		return new ActionMsg(8,"choice",gAct);
	}


	Message  *Dealer::AcceptStartComplete()
	{
		return new Message(3,"Start is complete for " + NameOf());
	}

	Message	 *Dealer::AcceptEndGame()
	{
		return new Message(4, NameOf() + " has ended the round.");
	}

	Message  *Dealer::AcceptTerminate()
	{   
		return new Message(5,"Terminate: " + NameOf());
	}

	Message	 *Dealer::CardReceivedMsg()
	{
		return new Message(7, NameOf() + " Received Card");
	}
/*
	ActionMsg	*Dealer::AcceptPlayerAction(Action::Choice decision)
	{
		return new ActionMsg(8, "Choice", decision);
	}*/
	void Dealer::doStartComplete()
	{
		me->getShuffledDeck();
		
		int time = theEventMgr.clock() +1; 
		CardMsg *cardMsg = (((Gambler *)gamblers2[currentGambler])->AcceptCard(deck[dealOrder[currentCard]].GetSuit(), deck[dealOrder[currentCard]].GetCardValue()));
		currentCard++;
		Event e( time , me , me, cardMsg);

		theEventMgr.postEvent(e);
		/*	This needs to start the process of dealing. This is what ConversationSim does, do something similar but different.
		int time = theEventMgr.clock() + 1;
		lastyou = 0;
		// Construct new message
		SpeakMsg *strMsg = ((Dealer *)you[lastyou])->AcceptQuestion("What is your name?");
 
		// Construct new Event
		Event e( time , me , you[lastyou] , strMsg );

		// Post Event
		theEventMgr.postEvent(e);
*/
	}
/*
	void Dealer::doQuestions(string question)
	{
		int time = theEventMgr.clock() + ansrDelay ;
		SpeakMsg *strMsg = AcceptAnswer("My name is:" + NameOf() + "!" );

		Event e( time , me , theEventMgr.getSendr() , strMsg );
		
		theEventMgr.postEvent(e);
	}

	void Dealer::doAnswers(string gAct)
	{
		ostream& simlog = simOutMgr.getStream();

		simOutMgr.newLine();
		simOutMgr.pushMargin();
		simlog << "At time: " << theEventMgr.clock();
		simlog << ", Dealer: " + NameOf() + " received the following response from: " + theEventMgr.getSendr()->NameOf();
		simOutMgr.advToMargin();
		simlog << gAct;
		simOutMgr.popMargin();
		simOutMgr.advToMargin();

		if( lastyou < interest-1 )
		{
			int time = theEventMgr.clock() + dealerStrategy;//this is a placeholder. will change.
			SpeakMsg *strMsg = ((Dealer *)you[++lastyou])->AcceptQuestion("What is your name?");
			
			// Construct new Event
			Event e( time , me , you[lastyou] , strMsg );

		    // Post Event
		    theEventMgr.postEvent(e);
		}//if

	}
*/
	void Dealer::doEndGame()
	{
		//print relevant info to log - this will change
		ostream& simlog = simOutMgr.getStream();

		simOutMgr.newLine();
		simOutMgr.pushMargin();
		simlog << "At time: " << theEventMgr.clock();
		simlog << ", Dealer: " + NameOf() + " has ended the game.";
		simOutMgr.advToMargin();
		simlog << *me;
		simOutMgr.popMargin();
		simOutMgr.advToMargin();

		//reset hand.
		for(int i=0; i<11; i++)
			hand[i] = Card();
		currentCard = 0;
		//start the new round
	}

	void Dealer::doTerminate()
	{
		ostream& simlog = simOutMgr.getStream();

		simOutMgr.newLine();
		simOutMgr.pushMargin();
		simlog << "At time: " << theEventMgr.clock();
		simlog << ", Dealer: " + NameOf() + " is terminating!";
		simOutMgr.advToMargin();
		simlog << *me;
		simOutMgr.popMargin();
		simOutMgr.advToMargin();
	}

	void Dealer::doCardReceived()
	{
		int time = theEventMgr.clock()+1;
		currentGambler++;
		if(currentGambler >= numGamblers)
			currentGambler = 0;
		if((currentGambler == numGamblers-1) && (numCards < 2))
		{
			CardMsg *cardMsg = (me->AcceptCard(deck[dealOrder[currentCard]].GetSuit(), deck[dealOrder[currentCard]].GetCardValue()));
			Event e( time , me , me, cardMsg);
			currentCard++;
			theEventMgr.postEvent(e);
		}
		else if(numCards<2)
		{
			CardMsg *cardMsg = (((Gambler *)gamblers2[currentGambler])->AcceptCard(deck[dealOrder[currentCard]].GetSuit(), deck[dealOrder[currentCard]].GetCardValue()));
			Event e( time , me , gamblers2[currentGambler], cardMsg);
			currentCard++;
			theEventMgr.postEvent(e);
		}
		else
		{
			Message *turnMsg = (((Gambler *)gamblers2[currentGambler])->AcceptTurn());
			Event e( time , me , gamblers2[currentGambler], turnMsg);
			currentCard++;
			theEventMgr.postEvent(e);
		}

	}

	void Dealer::doDealerAction(Action::Choice mychoice)
	{
		Action myAction = Action(mychoice);
		int time = theEventMgr.clock()+1;
		if(myAction.GetChoice()==0)
		{
			Message *endGameMsg = (me->AcceptEndGame());
			Event e( time, me, me, endGameMsg);
			theEventMgr.postEvent(e);
		}
		else
		{
			CardMsg *cardMsg = (me->AcceptCard(deck[dealOrder[currentCard]].GetSuit(), deck[dealOrder[currentCard]].GetCardValue()));
			Event e( time , me , me, cardMsg);
			currentCard++;
			theEventMgr.postEvent(e);
		}
	}
	void Dealer::doPlayerAction(Action::Choice theirchoice)
	{
		Action theirAction = Action(theirchoice);
		int time = theEventMgr.clock()+1;
		if((currentGambler != numGamblers-1) && (theirAction.GetChoice()==0))
		{
			currentGambler++;
			Message *turnMsg (((Gambler *)gamblers2[currentGambler])->AcceptTurn());
			Event e( time, me, gamblers2[currentGambler], turnMsg);
			theEventMgr.postEvent(e);
		}
		else if((currentGambler == numGamblers-1) && (theirAction.GetChoice()==0))
		{
			currentGambler++;
			Message *turnMsg (me->AcceptTurn());
			Event e( time, me, me, turnMsg);
			theEventMgr.postEvent(e);
		}
		else 
		{
			CardMsg *cardMsg = (((Gambler *)gamblers2[currentGambler])->AcceptCard(deck[dealOrder[currentCard]].GetSuit(), deck[dealOrder[currentCard]].GetCardValue()));
			Event e( time, me, gamblers2[currentGambler], cardMsg);
			theEventMgr.postEvent(e);
		}

	}

	void Dealer::doAcceptTurn()
	{/*
//		decision = Action();
		int choice = 0;
		ostream& simlog = simOutMgr.getStream();
		int row = (totalvalue-4);
		
		int dealerupcard=0;
		dealerupcard=dealer->GetUpCard();
		int column = (dealerupcard-2);
		
		for(int i = 0; i < numCards; i++)
		{
			if(flag[i]>0)
			{
				row=row+10;
				break;
			}
		}
		
		choice = playerStrategy[column][row];
		
		decision = (Action::Choice)choice;
		simOutMgr.newLine();
		simOutMgr.pushMargin();
		simlog << "At time: " << theEventMgr.clock() + 1;
		simlog << ", Gambler: " + NameOf() + " chose ";
		simlog << decision;
		simOutMgr.advToMargin();
		simlog << decision;
		simOutMgr.popMargin();
		simOutMgr.advToMargin();

		//if( lastyou < interest-1 )
		//{
			int time = theEventMgr.clock() + ansrDelay; //removed Questdelay. Arbitrarily add 1
		//	SpeakMsg *strMsg = ((Gambler *)you[++lastyou])->AcceptQuestion("What is your name?");
			ActionMsg *choiceMsg = dealer->AcceptGamblerAction(decision);
		
			// Construct new Event
		//	Event e( time , me , you[lastyou] , strMsg );
			Event e( time , me, dealer, choiceMsg);
		
			// Post Event
		 //   theEventMgr.postEvent(e);
			theEventMgr.postEvent(e);
		
			//}//if

			*/
	}
	void Dealer::doAcceptCard(int value, Card::Suit mysuit)
	{
		hand[numCards-1] = Card(value, mysuit);
		numCards++;

		for(int i=0; i<numCards; i++)
		{
			flag[i]=0;
			cardvalue[i] = hand[i].GetCardValue();
			totalvalue += cardvalue[i];
		}

		for(int i = 0; i<numCards; i++)
		{
			if(hand[i].GetCardValue()==11)
				flag[i]=1;
		}
		for(int i = 0; i<numCards; i++)
		{
			if((flag[i]=1) && (totalvalue > 21))
			{
				hand[i].SetCardValue(1);
				flag[i]=0;
				totalvalue=totalvalue-10;
			}

		}
		int time = theEventMgr.clock() + 1 ;
		//SpeakMsg *strMsg = AcceptAnswer("My name is:" + NameOf() + "!" ); Not being used kept for posterity
		Message *cardRec = me->CardReceivedMsg();
		
		Event e( time , me , theEventMgr.getSendr() , cardRec );
		
		theEventMgr.postEvent(e);
	}

	void Dealer::getShuffledDeck()
	{
		deck[0] = Card(2, Card::Suit::Spades);
		deck[1] = Card(3, Card::Suit::Spades);
		deck[2] = Card(4, Card::Suit::Spades);
		deck[3] = Card(5, Card::Suit::Spades);
		deck[4] = Card(6, Card::Suit::Spades);
		deck[5] = Card(7, Card::Suit::Spades);
		deck[6] = Card(8, Card::Suit::Spades);
		deck[7] = Card(9, Card::Suit::Spades);
		deck[8] = Card(10, Card::Suit::Spades);
		deck[9] = Card(10, Card::Suit::Spades);
		deck[10] = Card(10, Card::Suit::Spades);
		deck[11] = Card(10, Card::Suit::Spades);
		deck[12] = Card(11, Card::Suit::Spades);

		deck[13] = Card(2, Card::Suit::Hearts);
		deck[14] = Card(3, Card::Suit::Hearts);
		deck[15] = Card(4, Card::Suit::Hearts);
		deck[16] = Card(5, Card::Suit::Hearts);
		deck[17] = Card(6, Card::Suit::Hearts);
		deck[18] = Card(7, Card::Suit::Hearts);
		deck[19] = Card(8, Card::Suit::Hearts);
		deck[20] = Card(9, Card::Suit::Hearts);
		deck[21] = Card(10, Card::Suit::Hearts);
		deck[22] = Card(10, Card::Suit::Hearts);
		deck[23] = Card(10, Card::Suit::Hearts);
		deck[24] = Card(10, Card::Suit::Hearts);
		deck[25] = Card(11, Card::Suit::Hearts);

		deck[26] = Card(2, Card::Suit::Clubs);
		deck[27] = Card(3, Card::Suit::Clubs);
		deck[28] = Card(4, Card::Suit::Clubs);
		deck[29] = Card(5, Card::Suit::Clubs);
		deck[30] = Card(6, Card::Suit::Clubs);
		deck[31] = Card(7, Card::Suit::Clubs);
		deck[32] = Card(8, Card::Suit::Clubs);
		deck[33] = Card(9, Card::Suit::Clubs);
		deck[34] = Card(10, Card::Suit::Clubs);
		deck[35] = Card(10, Card::Suit::Clubs);
		deck[36] = Card(10, Card::Suit::Clubs);
		deck[37] = Card(10, Card::Suit::Clubs);
		deck[38] = Card(11, Card::Suit::Clubs);

		deck[39] = Card(2, Card::Suit::Diamonds);
		deck[40] = Card(3, Card::Suit::Diamonds);
		deck[41] = Card(4, Card::Suit::Diamonds);
		deck[42] = Card(5, Card::Suit::Diamonds);
		deck[43] = Card(6, Card::Suit::Diamonds);
		deck[44] = Card(7, Card::Suit::Diamonds);
		deck[45] = Card(8, Card::Suit::Diamonds);
		deck[46] = Card(9, Card::Suit::Diamonds);
		deck[47] = Card(10, Card::Suit::Diamonds);
		deck[48] = Card(10, Card::Suit::Diamonds);
		deck[49] = Card(10, Card::Suit::Diamonds);
		deck[50] = Card(10, Card::Suit::Diamonds);
		deck[51] = Card(11, Card::Suit::Diamonds);

		for(int j = 0; j<52; j++)
		{
			dealOrder[j] = -1;
		}

		int random;
		srand(time(0));
		
		

		for(int l = 0; l<52; l++)
		{
		   int flag = 0;
		   random = rand() % 52;
		   for(int k = 0; k<52; k++)
		   {
			   if(dealOrder[k]==random)
			   {
				flag=1;
				break;
			   }
		   }
			if(flag==0)
			{
				dealOrder[l]=random;
			}
			else
				l--;
		}
	}
	
////////////////////////////////////////////////////////////////////// Gambler

	Gambler::Gambler():Agent()
	{
	}


	Gambler::~Gambler()
	{
	}


	void Gambler::Extract() throw(TokenError)
	{
			string token;
			ifstream& fin = simInMgr.getStream();


			// Parse opening token
			fin >> token;
			if ( token != "Gambler{" ) 
			    throw TokenError(string("Incorrect Token, '" + token + "', expected 'Gambler{' !"),
                                 string("Gambler::Extract()"));
			
			// Parse data members
			Get();

			// Parse closing token
			fin >> token; 
			if ( token != "}Gambler" ) 
				throw TokenError(string("Incorrect Token '" + token + "', expected token '}Gambler' !"),
                                 string("Gambler::Get()"));
	}

	void Gambler::Get() throw(TokenError)
	{
		string token;
		ifstream& fin = simInMgr.getStream();

		// parse inherited members 
		Agent::Get(); 
//NEW		
		// parse token "bettingstrategy"
		fin >> token;
		if ( token != "bettingstrategy:" ) 
		   throw TokenError(string("Incorrect Token '" + token + "', expected 'bettingstrategy:' !"),
                            string("Gambler::Get(@1)"));

		// Parse player strategy
		for (int i=0; i<26; i++)
		{
			for(int j = 0; j<10; j++) 
			{
			fin >> token;
			playerStrategy[j][i] = atoi(token.c_str());  
			}
		}
//END NEW	
		// parse token "AnsrDelay"
		fin >> token; 
		if ( token != "ansrdelay:" ) 
		throw TokenError(string("Incorrect Token '" + token + "', expected 'ansrdelay:' !"),
                         string("Gambler::Get(@2)"));

		// Parse answer delay
		fin >> token;
		ansrDelay = atoi(token.c_str());
		
		//startDelay is arbitrarily set to 1. This is used during the initialization of each Gambler.
		startDelay = 1;

/* This can be deleted, kept for future reference just in case
		// parse token "scandelay"
		fin >> token; 
		if ( token != "scandelay:" ) 
		throw TokenError(string("Incorrect Token '" + token + "', expected 'scandelay:' !"),
                         string("Gambler::Get(@3)"));


		// Parse scandelay
		fin >> token;
		scanDelay = atoi(token.c_str());

		// parse token "interest"
		fin >> token; 
		if ( token != "interest:" ) 
		throw TokenError(string("Incorrect Token '" + token + "', expected 'interest:' !"),
                         string("Gambler::Get(@4)"));

		// Parse interest
		fin >> token;
		interest = atoi(token.c_str());
*/
	}

	void Gambler::Insert()
	{
		ostream& simlog = simOutMgr.getStream();

		simOutMgr.pushMargin();
		simlog << "Gambler{ ";
		Put();
		simOutMgr.advToMargin();
		simlog << "}Gambler ";
		simOutMgr.popMargin();
	}

	void Gambler::Put()
	{
		ostream& simlog = simOutMgr.getStream();
	
		simOutMgr.pushMargin();
		Agent::Put();
		simOutMgr.advToMargin();
		//simlog << " playerStrategy: "; 
		//simlog << playerStrategy[][];
		//simOutMgr.advToMargin();
		simlog << " ansrdelay: "  << ansrDelay;
		simOutMgr.advToMargin();
		simlog << " startdelay: "  << startDelay;
		/* This can be deleted, kept for future reference just in case
		simOutMgr.advToMargin();
		simlog << " interest: "   << interest;
		*/
		simOutMgr.popMargin();
	}


	void Gambler::Initialize(MSGPTR players)
	{
		// Obtaining player's handle
		me  = (Gambler *)((Players *)players)->getAgent(NameOf());
		
		/* This can be deleted, kept for future reference just in case
		// Pick and Agent at random to send a question to.
		you = ((Players *)players)->getOthers(interest);
        */

		//This function still needs to be created by Clint/Chantelle 
		//to return a pointer to the dealer for the gambler to use for the rest of the game
		dealer2 = (Dealer *)((Players *)players)->getDealer();

		numCards = 0;
		for(int i = 0; i<11; i++)
		{
		hand[i] = Card();
		}

		int time = theEventMgr.clock() + startDelay;
		// Construct new message
		Message *startMsg = ((Gambler *)me)->AcceptStartComplete();
 
		// Construct new Event
		Event e( time, me, me, startMsg );

		// Post Event
		theEventMgr.postEvent(e);

	}

	 void Gambler::Dispatch  (MSGPTR msg)
	{
		int h          = msg->getHandler();
		switch( h )
		{
		case 1: { 
				//	string content = ((SpeakMsg *)msg)->getContent(); Not being used. Kept for posterity
					int value = ((CardMsg *)msg)->getValue();
					Card::Suit mysuit = ((CardMsg *)msg)->getSuit();
					doAcceptCard(value, mysuit);
					break;
				}
		case 2: {
					//string content = ((SpeakMsg *)msg)->getContent();
					doAcceptTurn();
					break;
				}
		case 3: doStartComplete(); break;
		case 4: doEndGame(); break;
		case 5: doTerminate(); break;
		default: throw AppError("Undefined handler ID!", "Gambler::Dispatch()");
		}
        
	}//Dispatch

	CardMsg *Gambler::AcceptCard(Card::Suit mysuit, int value)
	{
		return new CardMsg(1, "Card Message", mysuit, value);
	}

	Message *Gambler::AcceptTurn()
	{
		return new Message(2,"It is" + NameOf() + "'s turn.");
	}

	Message  *Gambler::AcceptStartComplete()
	{
		return new Message(3, "Start is completed for " + NameOf());
	}
	Message	 *Gambler::AcceptEndGame()
	{
		return new Message(4, NameOf() + " has ended the round.");
	}
	Message  *Gambler::AcceptTerminate()
	{   
		return new Message(5,"Terminate: " + NameOf());
	}


	void Gambler::doStartComplete()
	{
		// Wait to receieve another message
		// This Function left intentionally blank



		/* This can be deleted, kept for future reference just in case
		int time = theEventMgr.clock() + 1; //Removed adding quest delay
		lastyou = 0;

		// Construct new message
		//SpeakMsg *strMsg = ((Gambler *)you[lastyou])->AcceptQuestion("What is your name?");
		Message *startMsg = ((Gambler *)me)->AcceptStartComplete("I have been created.");

		// Construct new Event
		Event e( time , me , me , startMsg );

		// Post Event
		theEventMgr.postEvent(e);
		*/ 
	}

	void Gambler::doAcceptCard(int value, Card::Suit mysuit)
	{
		hand[numCards-1] = Card(value, mysuit);
		numCards++;

		for(int i=0; i<numCards; i++)
		{
			flag[i]=0;
			cardvalue[i] = hand[i].GetCardValue();
			totalvalue += cardvalue[i];
		}

		for(int i = 0; i<numCards; i++)
		{
			if(hand[i].GetCardValue()==11)
				flag[i]=1;
		}
		for(int i = 0; i<numCards; i++)
		{
			if((flag[i]=1) && (totalvalue > 21))
			{
				hand[i].SetCardValue(1);
				flag[i]=0;
				totalvalue=totalvalue-10;
			}

		}
		int time = theEventMgr.clock() + 1 ;
		//SpeakMsg *strMsg = AcceptAnswer("My name is:" + NameOf() + "!" ); Not being used kept for posterity
		Message *cardRec = dealer2->CardReceivedMsg();
		
		Event e( time , me , theEventMgr.getSendr() , cardRec );
		
		theEventMgr.postEvent(e);
	}

	void Gambler::doAcceptTurn()
	{
//		decision = Action();
		int choice = 0;
		ostream& simlog = simOutMgr.getStream();
		int row = (totalvalue-4);
		
		int dealerupcard=0;
		dealerupcard=dealer2->GetUpCard();
		int column = (dealerupcard-2);
		
		for(int i = 0; i < numCards; i++)
		{
			if(flag[i]>0)
			{
				row=row+10;
				break;
			}
		}
		
		choice = playerStrategy[column][row];
		
		decision = (Action::Choice)choice;
		simOutMgr.newLine();
		simOutMgr.pushMargin();
		simlog << "At time: " << theEventMgr.clock();
		simlog << ", Gambler: " + NameOf() + " chose ";
		simlog << decision;
		simOutMgr.advToMargin();
		simlog << decision;
		simOutMgr.popMargin();
		simOutMgr.advToMargin();

		//if( lastyou < interest-1 )
		//{
			int time = theEventMgr.clock() + ansrDelay; //removed Questdelay. Arbitrarily add 1
		//	SpeakMsg *strMsg = ((Gambler *)you[++lastyou])->AcceptQuestion("What is your name?");
			ActionMsg *choiceMsg = dealer2->AcceptGamblerAction(decision);
		
			// Construct new Event
		//	Event e( time , me , you[lastyou] , strMsg );
			Event e( time , me, dealer2, choiceMsg);
		
			// Post Event
		 //   theEventMgr.postEvent(e);
			theEventMgr.postEvent(e);
		
			//}//if

	}

	void Gambler::doEndGame()
	{
		ostream& simlog = simOutMgr.getStream();

		//Write to output file that this gambler has ended the game
		simOutMgr.newLine();
		simOutMgr.pushMargin();
		simlog << "At time: " << theEventMgr.clock();
		simlog << ", Gambler: " + NameOf() + " has ended the game.";
		simOutMgr.advToMargin();
		simlog << *me;
		simOutMgr.popMargin();
		simOutMgr.advToMargin();
		
		//increment time by 1
		int time = theEventMgr.clock() + 1; 
		
		//Re-initialize all cards in hand to 0.
		for (int i = 0; i < 11; i++)
		{
			hand[i] = Card();
		}

		//Create a message pointer that points to the message Dealer::AcceptEndGame() creates
		Message *endMsg = ((Dealer *)dealer2)->AcceptEndGame();

		//Create and post an event
		Event e( time, me, dealer2, endMsg);
		theEventMgr.postEvent(e);
	}
	void Gambler::doTerminate()
	{
		ostream& simlog = simOutMgr.getStream();

		simOutMgr.newLine();
		simOutMgr.pushMargin();
		simlog << "At time: " << theEventMgr.clock();
		simlog << ", Gambler: " + NameOf() + " is terminating!";
		simOutMgr.advToMargin();
		simlog << *me;
		simOutMgr.popMargin();
		simOutMgr.advToMargin();
	}




/*
////////////////////////////////////////////////////////////////////////Conversation

	Conversation::Conversation()
	{
	    ifstream& fin = simInMgr.getStream();

		string token;
		// Parse opening token
		fin >> token;
		if ( token != "Conversation{" ) 
		   throw AppError(string("Incorrect Token '" + token + "', expected token 'Conversation{' !"),
                          string("Conversation::Conversation()"));

		// parse data member # of students
		fin >> token;
		if ( token != "#students:" ) 
		     throw AppError(string("Incorrect Token '" + token + "', expected token '#students:' !"),
                            string("Conversation::Conversation()"));
        fin >> token;
		numStudents = atoi(token.c_str());
		if( numStudents <= 0 )
            throw AppError(string("Number of students is not positive!"),
                            string("Conversation::Conversation()"));
        students    = new AGENTPTR[numStudents];
		// Construct Student instances
        for(int i = 0; i < numStudents; i++) 
		{
			students[i] = new Student();
			students[i]->Extract();
		}

		// Parse closing token
		fin >> token;
		if ( token != "}Conversation" ) 
			throw AppError(string("Incorrect Token '" + token + "', expected token '}Conversation' !"),
                          string("Conversation::Conversation()"));

		numEvents = 0;

		putHeader();

	}

	Conversation::~Conversation()
	{
		for ( int i = 0 ; i < numStudents ; i++ ) delete students[i];
		delete[] students;
	}


	void Conversation::Initialize()
	{
		ostream& simlog = simOutMgr.getStream();

		// Construct new Players object
		Players *players = new Players(numStudents);
		int i;

		// Set students
		for( i=0; i < numStudents; i++ )players->setAgent( students[i]->NameOf() , students[i] );
	
		// Initialize students
		for( i=0; i < numStudents; i++ )students[i]->Initialize( players );

        simOutMgr.newLine();
		simlog << *players;
        simOutMgr.newLine();

		delete players;
	}

	void Conversation::Simulate()
	{
		Event    e;
        Message *msg;
		string   token;
		ostream& simlog = simOutMgr.getStream();


		while( theEventMgr.moreEvents() )
		{
			//retrive next event and message
			e   = theEventMgr.getNextEvent();
            msg = e.getMsg();
		
			// Output to simlog
			simOutMgr.newLine();
			simlog << e;
			simOutMgr.newLine();

			// Dispatch
			e.getRecvr()->Dispatch( msg );  
			
            // destruct message
			delete msg; 

			// Update statistical data
			lastEvent = e.getTime(); 
			numEvents++;
		}
		//code to terminate all Students
		for( int i = 0; i < numStudents; i++)
		{
			students[i]->Dispatch(((Student *)students[i])->AcceptTerminate());
		}
	}//Simulate

	void Conversation::Insert()
	{
		ostream& simlog = simOutMgr.getStream();

        simOutMgr.newLine();
	    simOutMgr.pushMargin();
		simlog << "Conversation{ ";
	    simOutMgr.pushMargin();

		simlog << "#students: " << numStudents;
		simOutMgr.advToMargin();

		for (int i = 0 ; i < numStudents ; i++ ) 
		{ simlog << *((Student *)students[i]);
		  simOutMgr.advToMargin();
		}
		simOutMgr.popMargin();
		simOutMgr.advToMargin();
		simlog << "}Conversation ";
		simOutMgr.popMargin();
		simOutMgr.advToMargin();
	}

	void Conversation::WrapUp()
	{
		ostream& simlog = simOutMgr.getStream();

		simOutMgr.newLine();
		simOutMgr.pushMargin();

		simlog << "Simulation Statistics:";

		simOutMgr.advToMargin();
		simlog << "Number of events : " << numEvents;

		simOutMgr.advToMargin();
		simlog << "Time of Last event : " <<  lastEvent;

		simOutMgr.advToMargin();
		simlog << "Total simulation time : " << theEventMgr.clock();

		simOutMgr.advToMargin();
		simOutMgr.popMargin();
		simOutMgr.newLine();

	}
*/
	////////////////////////////////////////////////////////////////////////Blackjack

	Blackjack::Blackjack()
	{
	    ifstream& fin = simInMgr.getStream();

		string token;
		
		// Parse opening token
		fin >> token;
		if ( token != "Blackjack{" ) 
		   throw AppError(string("Incorrect Token '" + token + "', expected token 'Blackjack{' !"),
                          string("Blackjack::Blackjack()"));

		// parse data member # of gamblers
		fin >> token;
		if ( token != "#gamblers:" ) 
		     throw AppError(string("Incorrect Token '" + token + "', expected token '#gamblers:' !"),
                            string("Blackjack::Blackjack()"));
		fin >> token;
		numGamblers = atoi(token.c_str());
		if( numGamblers <= 0 )
            throw AppError(string("Number of gamblers is not positive!"),
                            string("Blackjack::Blackjack()"));
        //gamblers    = new Gambler[numGamblers];
		
		// Construct Gambler instances
        for(int i = 0; i < numGamblers; i++) 
		{
			gamblers[i] = Gambler();
			gamblers[i].Extract();
		}

		// Construct Dealer Instance
		dealer = Dealer();
		dealer.Extract();
		
		// Parse closing token
		fin >> token;
		if ( token != "}Blackjack" ) 
			throw AppError(string("Incorrect Token '" + token + "', expected token '}Blackjack' !"),
                          string("Blackjack::Blackjack()"));

		//Initialize event counter
		numEvents = 0;

		//Place header into the output file
		putHeader();

	}//Blackjack::Constructor()

	Blackjack::~Blackjack()
	{
		//Delete Gamblers
		//for ( int i = 0 ; i < numGamblers ; i++ ) delete gamblers[i];
		//delete[] gamblers;

		//Delete Dealer
		//delete dealer;
	}//Blackjack::Destructor()


	void Blackjack::Initialize()
	{
		ostream& simlog = simOutMgr.getStream();

		// Construct new Players object
		Players *players = new Players(numGamblers);
		int i;

		// Set gamblers
		for( i=0; i < numGamblers; i++ )players->setAgent( gamblers[i].NameOf() , &gamblers[i] );
	
		// Set dealer
		players->setDealer(&dealer);
		// Initialize gamblers
		for( i=0; i < numGamblers; i++ )gamblers[i].Initialize( players );

		// Initialize dealer
		dealer.Initialize( players);

        simOutMgr.newLine();
		simlog << *players;
        simOutMgr.newLine();

		delete players;
	}//Blackjack::Initialize()

	void Blackjack::Simulate()
	{
		Event    e;
        Message *msg;
		string   token;
		ostream& simlog = simOutMgr.getStream();


		while( theEventMgr.moreEvents() )
		{
			//retrive next event and message
			e   = theEventMgr.getNextEvent();
            msg = e.getMsg();
		
			// Output to simlog
			simOutMgr.newLine();
			simlog << e;
			simOutMgr.newLine();

			// Dispatch
			e.getRecvr()->Dispatch( msg );  
			
            // destruct message
			delete msg; 

			// Update statistical data
			lastEvent = e.getTime(); 
			numEvents++;
		}
		//code to terminate all Gamblers
		for( int i = 0; i < numGamblers; i++)
		{
			gamblers[i].Dispatch(((Gambler)gamblers[i]).AcceptTerminate());
		}

		//code to terminate the dealer
		dealer.Dispatch(((Dealer)dealer).AcceptTerminate());

	}//Blackjack::Simulate()

	void Blackjack::Insert()
	{
		ostream& simlog = simOutMgr.getStream();

        simOutMgr.newLine();
	    simOutMgr.pushMargin();
		simlog << "Blackjack{ ";
	    simOutMgr.pushMargin();

		simlog << "#gamblers: " << numGamblers;
		simOutMgr.advToMargin();

		//Gamblers output
		for (int i = 0 ; i < numGamblers ; i++ ) 
		{ simlog << ((Gambler )gamblers[i]);
		  simOutMgr.advToMargin();
		}

		//Dealer output
		simlog<< ((Dealer)dealer);
		simOutMgr.advToMargin();

		simOutMgr.popMargin();
		simOutMgr.advToMargin();
		simlog << "}Blackjack ";
		simOutMgr.popMargin();
		simOutMgr.advToMargin();
	}//Blackjack::Insert()

	void Blackjack::WrapUp()
	{
		ostream& simlog = simOutMgr.getStream();

		simOutMgr.newLine();
		simOutMgr.pushMargin();

		simlog << "Simulation Statistics:";

		simOutMgr.advToMargin();
		simlog << "Number of events : " << numEvents;

		simOutMgr.advToMargin();
		simlog << "Time of Last event : " <<  lastEvent;

		simOutMgr.advToMargin();
		simlog << "Total simulation time : " << theEventMgr.clock();

		simOutMgr.advToMargin();
		simOutMgr.popMargin();
		simOutMgr.newLine();

	}//Blackjack::WrapUp()


}//SimModels
